/*
purpose: bitmap level crc checking for volume, should set granularity as 512.
*/

#include "config.h"

#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

typedef struct {
        uint32_t set : 1;
        uint32_t crc : 31;
} check_bitmap_unit_t;

typedef struct {
        uint64_t capacity;
        check_bitmap_unit_t check_units[0];
} check_bitmap_context_t;

uint32_t testcrc(void *buf, uint32_t size)
{
        uint32_t crc = 0;

        for (int i = 0; i < size / sizeof(uint32_t); i++) {
                crc += ((uint32_t *)buf)[i];
        }

        return crc;
}

uint64_t check_bitmap_size = 0;
void check_bitmap_alloc(void **context, uint64_t capacity)
{
        check_bitmap_context_t *check_bitmap = malloc(capacity / 512 * sizeof(check_bitmap_unit_t) + sizeof(check_bitmap_context_t));
        memset(check_bitmap, 0, capacity / 512 * sizeof(check_bitmap_unit_t) + sizeof(check_bitmap_context_t));

        check_bitmap->capacity = capacity;

        *context = check_bitmap;
}

void check_bitmap_free(void *context) { free(context); }

void check_bitmap_set(void *context, uint64_t off, void *buf)
{
        check_bitmap_context_t *check_bitmap = (check_bitmap_context_t *)context;

        if (off >= check_bitmap->capacity)
                return;

        uint32_t index = off / 512;
        check_bitmap->check_units[index].set = 1;
        check_bitmap->check_units[index].crc = testcrc(buf, 512);
}

void check_bitmap_check(void *context, uint64_t off, void *buf)
{
        check_bitmap_context_t *check_bitmap = (check_bitmap_context_t *)context;

        if (off >= check_bitmap->capacity)
                return;

        uint32_t index = off / 512;
        if (!check_bitmap->check_units[index].set)
                return;

        assert(check_bitmap->check_units[index].crc == (0x7FFFFFFF & testcrc(buf, 512)));// 31 bit of integer.
}